#if UNITY_EDITOR
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.Concurrent;
using UnityEngine;
using UnityEditor;
using Net.Helper;
using Newtonsoft_X.Json;
#if HYBRIDCLR
using HybridCLR.Editor;
using HybridCLR.Editor.Commands;
#endif
using Debug = UnityEngine.Debug;

namespace GameCore
{
    [CustomEditor(typeof(AssetBundleBuilder))]
    public class AssetBundleBuilderEditor : Editor
    {
        private AssetBundleBuilder assetBundleBuilder;
        private readonly Dictionary<FilterOptions, string[]> filterOptionDict = new()
        {
            { FilterOptions.AnimationClip, new string[]{ ".anim" } },
            { FilterOptions.AudioClip, new string[]{ ".ogg", ".wav", ".mp3" } },
            { FilterOptions.AudioMixer, new string[]{ ".mixer" } },
            { FilterOptions.ComputeShader, new string[]{ ".compute" } },
            { FilterOptions.Font, new string[]{ ".ttf", ".fontsettings", ".TTF" } },
            { FilterOptions.GUISkin, new string[]{ ".guiskin" } },
            { FilterOptions.Material, new string[]{ ".mat" } },
            { FilterOptions.Mesh, new string[]{ ".fbx", ".FBX", ".obj" } },
            { FilterOptions.Model, new string[]{ ".fbx", ".FBX", ".obj" } },
            { FilterOptions.PhysicMaterial, new string[]{ ".physicMaterial" } },
            { FilterOptions.Prefab, new string[]{ ".prefab" } },
            { FilterOptions.Scene, new string[]{ ".unity" } },
            { FilterOptions.Script, new string[]{ ".cs" } },
            { FilterOptions.Shader, new string[]{ ".shader" } },
            { FilterOptions.Sprite, new string[]{ ".jpg", ".png", ".bmp", ".tiff", ".psd", ".svg", ".jpeg" } },
            { FilterOptions.Texture, new string[]{ ".jpg", ".png", ".bmp", ".tiff", ".psd", ".svg", ".jpeg" } },
            { FilterOptions.VideoClip, new string[]{ ".mp4", ".avi", ".mkv", ".flv", ".wmv" } },
        };
        private readonly ConcurrentQueue<Task> tasks = new();
        private readonly ConcurrentQueue<ValueTuple<string, float>> displayInfos = new();
        private int errorCount;

        private void OnEnable()
        {
            assetBundleBuilder = target as AssetBundleBuilder;
        }

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
#if HYBRIDCLR
            if (GUILayout.Button("BuildAssembly"))
            {
                CompileDllCommand.CompileDllActiveBuildTarget();
                CopyHotUpdateAssembliesToStreamingAssets(assetBundleBuilder.hotfixPath);
            }
#endif
            if (GUILayout.Button("BuildGameConfig"))
                ExcelTools.GenerateExcelData(assetBundleBuilder.tablePath);
            if (GUILayout.Button("BuildGameConfigScript"))
                ExcelTools.GenerateExcelDataAll(assetBundleBuilder.tablePath, assetBundleBuilder.tableScriptPath);
            if (GUILayout.Button("BuildAssetBundle"))
                BuildAssetBundle();
            if (GUILayout.Button("打开资源包目录"))
            {
                var outputPath = $"{assetBundleBuilder.outputPath}/{assetBundleBuilder.config.platform}/";
                outputPath = PathHelper.Combine(outputPath, "/");
                Process.Start("explorer.exe", outputPath);
            }
            if (GUILayout.Button("打开持久化目录"))
            {
                var outputPath = Application.persistentDataPath;
                outputPath = PathHelper.Combine(outputPath, "/");
                Process.Start("explorer.exe", outputPath);
            }
        }

        private async void BuildAssetBundle()
        {
            if (assetBundleBuilder.config == null)
            {
                Debug.LogError("请设置config引用!");
                return;
            }
            var outputPath = $"{assetBundleBuilder.outputPath}/{assetBundleBuilder.config.platform}/{assetBundleBuilder.config.version}/";
            var outputPathTemp = $"{assetBundleBuilder.outputPath}Temp/{assetBundleBuilder.config.platform}/{assetBundleBuilder.config.version}/";
            var outputPathUpdate = $"{assetBundleBuilder.outputPath}Update/{assetBundleBuilder.config.platform}/{assetBundleBuilder.config.version}/";
            if (assetBundleBuilder.clearFolders)
            {
                if (Directory.Exists(outputPath))
                    Directory.Delete(outputPath, true);
                if (Directory.Exists(outputPathTemp))
                    Directory.Delete(outputPathTemp, true);
                if (assetBundleBuilder.copyToStreamingAssets)
                {
                    var m_streamingPath = $"{Application.streamingAssetsPath}/AssetBundles/{assetBundleBuilder.config.platform}/{assetBundleBuilder.config.version}/";
                    if (Directory.Exists(m_streamingPath))
                        Directory.Delete(m_streamingPath, true);
                }
            }
            if (!Directory.Exists(outputPath))
                Directory.CreateDirectory(outputPath);
            if (!Directory.Exists(outputPathTemp))
                Directory.CreateDirectory(outputPathTemp);
            if (Directory.Exists(outputPathUpdate))
                Directory.Delete(outputPathUpdate, true);
            Directory.CreateDirectory(outputPathUpdate);
            var allAssetBundleBuildList = new ConcurrentBag<AssetBundleBuild>();
            var assetPackageManagerNew = new AssetPackageManager();
            errorCount = 0;
            tasks.Clear();
            displayInfos.Clear();
            var abi = AssetBundleBuilder.Instance;
            var packageInfoDict = new Dictionary<string, AssetPackageInfo>();
            for (int i = 0; i < assetBundleBuilder.Packages.Count; i++)
            {
                var package = assetBundleBuilder.Packages[i];
                if (!package.enable)
                    continue;
                var assetPackage = new AssetPackage
                {
                    Name = package.name,
                    Encrypt = package.encrypt,
                };
                packageInfoDict.Add(package.name, new AssetPackageInfo(package.name, package.needing, null, 0U)
                {
                    EncryptJson = package.encryptJson,
                    CompressionJson = package.compressionJson,
                });
                var filters = new List<string>();
                foreach (var filterObject in package.filters)
                    filters.Add(AssetDatabase.GetAssetPath(filterObject));
                for (int j = 0; j < package.paths.Count; j++)
                {
                    var assetPath = AssetDatabase.GetAssetPath(package.paths[j]);
                    var isFolder = AssetDatabase.IsValidFolder(assetPath);
                    if (isFolder)
                        AssetBundleCollect(allAssetBundleBuildList, assetPackageManagerNew, assetPackage, assetPath, package, i / (float)assetBundleBuilder.Packages.Count, filters);
                    else
                        AddSinglePackage(allAssetBundleBuildList, assetPackageManagerNew, assetPackage, assetPath, package);
                }
                assetPackageManagerNew.Packages.Add(assetPackage);
            }
            void DisplayProgressBar(ref int number)
            {
                while (displayInfos.TryDequeue(out var displayInfo))
                {
                    EditorUtility.DisplayProgressBar("AssetBundleCollect", displayInfo.Item1, displayInfo.Item2);
                    if (number++ >= assetBundleBuilder.displaySleep)
                    {
                        Thread.Sleep(1);
                        number = 0;
                    }
                }
            }
            while (tasks.TryDequeue(out var task))
            {
                int number = 0;
                while (!task.IsCompleted)
                    DisplayProgressBar(ref number);
                DisplayProgressBar(ref number);
            }
            EditorUtility.ClearProgressBar();
            if (errorCount > 0)
            {
                Debug.Log("请先解决错误后再打包!");
                return;
            }
            Debug.Log($"收集的资源包数量:{allAssetBundleBuildList.Count} 资源文件数量:{assetPackageManagerNew.GetAssetInfoCount()}");
            var assetPackageManagerOld = new AssetPackageManager();
            assetPackageManagerOld.EditorInitPackages(assetBundleBuilder);
            var assetBundleBuildList = new HashSet<string>();
            foreach (var packageNew in assetPackageManagerNew.Packages)
            {
                var packageOld = assetPackageManagerOld.Packages.Where(package => package.Name == packageNew.Name).FirstOrDefault();
                foreach (var assetInfo in packageNew.AssetInfos)
                {
                    if (packageOld != null && packageOld.CheckMD5(assetInfo))
                        continue;
                    var assetBundleName = assetInfo.AssetBundleName;
                    assetBundleBuildList.Add(assetBundleName);
                    packageOld?.AddAssetInfo(assetInfo.AssetPath, assetInfo.AssetBundleName, assetInfo.MD5);
                }
                if (packageOld != null)
                {
                    for (int i = packageOld.AssetInfos.Count - 1; i >= 0; i--) //资源引用减量处理
                    {
                        var assetInfo = packageOld.AssetInfos[i];
                        if (File.Exists(assetInfo.AssetPath))
                            continue;
                        var assetBundleName = assetInfo.AssetBundleName;
                        assetBundleBuildList.Add(assetBundleName);
                        packageOld.AssetInfos.RemoveAt(i);
                    }
                    for (int i = packageOld.AssetBundleInfos.Count - 1; i >= 0; i--) //AB包减量处理
                    {
                        var assetBundleInfo = packageOld.AssetBundleInfos[i];
                        if (assetBundleInfo.GetAssetInfos().Count > 0)
                            continue;
                        var assetBundlePath = $"{outputPathTemp}{assetBundleInfo.Name}";
                        var assetBundleManifPath = $"{outputPathTemp}{assetBundleInfo.Name}.manifest";
                        if (File.Exists(assetBundlePath))
                            File.Delete(assetBundlePath);
                        if (File.Exists(assetBundleManifPath))
                            File.Delete(assetBundleManifPath);
                        assetBundleBuildList.Add(assetBundleInfo.Name);
                        packageOld.AssetBundleInfos.RemoveAt(i);
                    }
                }
            }
            if (assetBundleBuilder.incrementalPackaging)
                assetPackageManagerNew = assetPackageManagerOld;
            Debug.Log($"筛选后要构建的资源包数量:{assetBundleBuildList.Count}");
            if (assetBundleBuildList.Count == 0)
            {
                Debug.Log("没有增量更新包!");
                return;
            }
            //这里必须打的是全部包, Unity会生成.manifest文件记录资源哈希值，用于增量判断。不要删除这些文件
            //增量打包不要包含BuildAssetBundleOptions.ForceRebuildAssetBundle
            var assetBundleManifest = BuildPipeline.BuildAssetBundles(outputPathTemp, allAssetBundleBuildList.ToArray(), assetBundleBuilder.options, (BuildTarget)assetBundleBuilder.config.platform);
            if (assetBundleManifest == null) //取消打包
            {
                Debug.Log("取消打包!");
                return;
            }
            var fileStream = new FileStream($"{outputPathTemp}/package.tmp", FileMode.OpenOrCreate, FileAccess.ReadWrite);
            foreach (var package in assetPackageManagerNew.Packages)
            {
                var packagePath = $"{outputPath}/{package.Name}/";
                var packagePathUpdate = $"{outputPathUpdate}/{package.Name}/";
                if (!Directory.Exists(packagePath))
                    Directory.CreateDirectory(packagePath);
                if (!Directory.Exists(packagePathUpdate))
                    Directory.CreateDirectory(packagePathUpdate);
                var packageInfo = packageInfoDict[package.Name];
                fileStream.SetLength(0);
                package.AssetBundleInfos.Sort((a, b) => a.Name.CompareTo(b.Name)); //上面收集是多线程收集的, 每次收集的顺序都是不一样, 所以需要进行排序使其一致
                for (int i = package.AssetBundleInfos.Count - 1; i >= 0; i--)
                {
                    var assetBundleInfo = package.AssetBundleInfos[i];
                    var assetBundlePath = $"{outputPathTemp}{assetBundleInfo.Name}";
                    if (!File.Exists(assetBundlePath))
                    {
                        package.AssetBundleInfos.RemoveAt(i);
                        continue;
                    }
                    var dependencies = assetBundleManifest.GetDirectDependencies(assetBundleInfo.Name);
                    if (dependencies.Length > 0)
                        package.Dependencies[assetBundleInfo.Name] = dependencies;
                    var bytes = File.ReadAllBytes(assetBundlePath);
                    var isNewFile = assetBundleBuildList.Contains(assetBundleInfo.Name);
                    if (isNewFile && package.Encrypt) //增量更新的文件才需要加密，否则导致多次加密问题
                    {
                        EncryptHelper.ToEncrypt(assetBundleBuilder.config.password, bytes);
                        Debug.Log($"加密文件:{packagePath + assetBundleInfo.Name}完成!");
                    }
                    assetBundleInfo.MD5 = EncryptHelper.GetMD5(bytes);
                    assetBundleInfo.FileSize = bytes.Length;
                    File.WriteAllBytes(packagePath + assetBundleInfo.Name, bytes);
                    if (isNewFile)
                        File.WriteAllBytes(packagePathUpdate + assetBundleInfo.Name, bytes);
                    fileStream.Write(bytes);
                }
                fileStream.Position = 0; //位置归零后才能正确计算md5值
                fileStream.Flush();
                var assetPackageInfo = packageInfoDict[package.Name];
                assetPackageInfo.MD5 = EncryptHelper.GetMD5(fileStream);
                assetPackageInfo.FileSize = fileStream.Length;
                var packageJson = JsonConvert.SerializeObject(package, Formatting.Indented);
                var packageJsonBytes = Encoding.UTF8.GetBytes(packageJson);
                if (packageInfo.EncryptJson)
                    EncryptHelper.ToEncrypt(assetBundleBuilder.config.password, packageJsonBytes);
                if (packageInfo.CompressionJson)
                    packageJsonBytes = UnZipHelper.Compress(packageJsonBytes);
                File.WriteAllBytes($"{outputPath}{package.Name}.json", packageJsonBytes);
                File.WriteAllBytes($"{outputPathUpdate}{package.Name}.json", packageJsonBytes);
            }
            fileStream.Dispose();
            File.Delete($"{outputPathTemp}/package.tmp");
            if (assetBundleBuilder.config.useFirstPackage)
            {
                EditorUtility.DisplayProgressBar("AssetBundleCollect", $"正在压缩初始包...", 0f);
                foreach (var package in assetPackageManagerNew.Packages)
                {
                    var packagePath = $"{outputPath}/{package.Name}/";
                    var destPath = $"{outputPath}/{package.Name}.zip";
                    var destPathUpdate = $"{outputPathUpdate}/{package.Name}.zip";
                    await UnZipHelper.CompressFiles(packagePath, destPath, System.IO.Compression.CompressionLevel.Optimal, true, null,
                        (name, progress) => EditorUtility.DisplayProgressBar("AssetBundleCollect", $"正在压缩初始包:{name}", progress));
                    if (assetBundleBuilder.config.firstPackageInStreamingAssets)
                        File.Copy(destPath, $"{Application.streamingAssetsPath}/{package.Name}.zip", true);
                    var assetPackageInfo = packageInfoDict[package.Name];
                    fileStream = new FileStream(destPath, FileMode.Open);
                    assetPackageInfo.MD5 = EncryptHelper.GetMD5(fileStream); //如果使用压缩包, 则需要以压缩包md5来
                    assetPackageInfo.FileSize = fileStream.Length;
                    fileStream.Dispose();
                    File.Copy(destPath, destPathUpdate, true);
                }
                EditorUtility.ClearProgressBar();
            }
            var json = JsonConvert.SerializeObject(packageInfoDict.Values.ToList(), Formatting.Indented);
            var jsonBytes = Encoding.UTF8.GetBytes(json);
            File.WriteAllBytes(outputPath + "../version.json", jsonBytes);
            File.WriteAllBytes(outputPathUpdate + "../version.json", jsonBytes);
            if (assetBundleBuilder.copyToStreamingAssets)
            {
                var m_streamingPath = Application.streamingAssetsPath + "/AssetBundles/";
                DirectoryCopy(assetBundleBuilder.outputPath, m_streamingPath);
            }
            CheckAutoIncrement();
            AssetDatabase.Refresh();
            Debug.Log("构建资源完成!");
        }

        private string GetAssetBundleName(string assetPath, CollectType type)
        {
            string assetBundleName;
            if (type == CollectType.AllDirectoriesSplitHashName || type == CollectType.TopDirectoryOnlyHashName || type == CollectType.AllDirectoriesHashName)
                assetBundleName = EncryptHelper.GetMD5(assetPath);
            else
                assetBundleName = assetPath.Replace("\\", "_").Replace("/", "_").Replace(".", "_").Replace(" ", "").Replace("-", "_").ToLower();
            if (!string.IsNullOrEmpty(assetBundleBuilder.packageFormat))
                assetBundleName += "." + assetBundleBuilder.packageFormat;
            return assetBundleName;
        }

        private void AssetBundleCollect(ConcurrentBag<AssetBundleBuild> buildList, AssetPackageManager assetPackageManager, AssetPackage assetPackage, string assetPath, AssetBundlePackage package, float progress, List<string> filters)
        {
            displayInfos.Enqueue(($"收集路径:{assetPath}", progress));
            var type = package.type;
            SearchOption searchOption;
            if (type == CollectType.AllDirectories || type == CollectType.AllDirectoriesHashName) //只有这两种获取所有文件夹的文件，Split模式则不能使用
                searchOption = SearchOption.AllDirectories;
            else
                searchOption = SearchOption.TopDirectoryOnly;
            var files = Directory.GetFiles(assetPath, "*.*", searchOption).Where(s =>
            {
                if (s.EndsWith(".meta"))
                    return false;
                if (s.EndsWith(".cs"))
                    return false;
                s = s.Replace('\\', '/');
                foreach (var assetPath in filters)
                {
                    if (StringHelper.StartsWith(s, assetPath))
                        return false;
                }
                foreach (FilterOptions flag in Enum.GetValues(typeof(FilterOptions)))
                {
                    if (!package.filter.HasFlag(flag))
                        continue;
                    if (!filterOptionDict.TryGetValue(flag, out var expands))
                        continue;
                    foreach (var expand in expands)
                        if (s.EndsWith(expand))
                            return false;
                }
                return true;
            }).ToList();
            for (int i = files.Count - 1; i >= 0; i--)
            {
                files[i] = files[i].Replace('\\', '/');
                if (files[i].EndsWith(".unity"))
                {
                    var sceneAssetBundleName = AddSinglePackage(buildList, assetPackageManager, assetPackage, files[i], package);
                    files.RemoveAt(i);
                    displayInfos.Enqueue(($"收集资源包:{sceneAssetBundleName}完成!", progress));
                }
            }
            int count = 1;
            while (files.Count > 0)
            {
                long totalSize = 0;
                var assetBundleName = GetAssetBundleName(assetPath, type);
                int sizeIndex = files.Count;
                for (int i = 0; i < files.Count; i++)
                {
                    totalSize += new FileInfo(files[i]).Length;
                    if (totalSize >= assetBundleBuilder.singlePackageSize)
                    {
                        sizeIndex = i == 0 ? 1 : i; //解决不足1死循环问题
                        assetBundleName += "_" + count++;
                        break;
                    }
                }
                var assetNames = files.GetRange(0, sizeIndex);
                var addressableNames = new List<string>();
                files.RemoveRange(0, sizeIndex);
                var addressables = AssetBundleBuilder.Instance.config.addressables;
                for (int i = 0; i < assetNames.Count; i++)
                {
                    var lastModified = File.GetLastWriteTime(assetNames[i]);
                    var lastModified1 = File.GetLastWriteTime(assetNames[i] + ".meta");
                    var md5 = EncryptHelper.GetMD5($"{lastModified}-{lastModified1}");
                    var assetName = assetNames[i];
                    if (addressables)//资源名不包含路径和后缀
                    {
                        assetName = Path.GetFileNameWithoutExtension(assetName);
                        addressableNames.Add(assetName);
                    }
                    if (assetPackageManager.ContainsAssetInfo(assetName))
                    {
                        Interlocked.Increment(ref errorCount);
                        Debug.LogError($"资源{assetName}有同名, 可寻址模式资源不可同名!"); //资源名需要在所有ab中唯一（不能同名）
                        continue;
                    }
                    assetPackage.AddAssetInfo(assetName, assetBundleName, md5);
                }
                var assetBundleBuild = new AssetBundleBuild
                {
                    assetBundleName = assetBundleName,
                    assetNames = assetNames.ToArray(),
                    addressableNames = addressableNames.ToArray()
                };
                buildList.Add(assetBundleBuild);
                displayInfos.Enqueue(($"收集资源包:{assetBundleName}完成!", progress));
            }
            if (type < CollectType.AllDirectoriesSplit)
                return;
            var directories = Directory.GetDirectories(assetPath);
            if (directories.Length > 0)
            {
                for (int i = 0; i < directories.Length; i++)
                {
                    var directorie = directories[i].Replace('\\', '/');
                    bool isFilter = false;
                    foreach (var filterPath in filters)
                    {
                        if (StringHelper.StartsWith(directorie, filterPath))
                        {
                            isFilter = true;
                            break;
                        }
                    }
                    if (isFilter)
                        continue;
                    var task = Task.Run(() =>
                    {
                        AssetBundleCollect(buildList, assetPackageManager, assetPackage, directorie, package, progress, filters);
                    });
                    tasks.Enqueue(task);
                }
            }
        }

        private string AddSinglePackage(ConcurrentBag<AssetBundleBuild> buildList, AssetPackageManager assetPackageManager, AssetPackage assetPackage, string assetPath, AssetBundlePackage package)
        {
            var lastModified = File.GetLastWriteTime(assetPath);
            var lastModified1 = File.GetLastWriteTime(assetPath + ".meta");
            var md5 = EncryptHelper.GetMD5($"{lastModified}-{lastModified1}");
            var addressableNames = new List<string>();
            var addressables = AssetBundleBuilder.Instance.config.addressables;
            if (addressables)//资源名不包含路径和后缀
            {
                assetPath = Path.GetFileNameWithoutExtension(assetPath);
                addressableNames.Add(assetPath);
            }
            if (assetPackageManager.ContainsAssetInfo(assetPath))
            {
                Interlocked.Increment(ref errorCount);
                Debug.LogError($"资源{assetPath}有同名, 可寻址模式资源不可同名!"); //资源名需要在所有ab中唯一（不能同名）
                return string.Empty;
            }
            var sceneAssetBundleName = GetAssetBundleName(assetPath, package.type);
            assetPackage.AddAssetInfo(assetPath, sceneAssetBundleName, md5);
            var assetBundleBuild = new AssetBundleBuild
            {
                assetBundleName = sceneAssetBundleName,
                assetNames = new string[] { assetPath },
                addressableNames = addressableNames.ToArray()
            };
            buildList.Add(assetBundleBuild);
            return sceneAssetBundleName;
        }

        public string CheckAutoIncrement()
        {
            if (assetBundleBuilder.autoIncrement)
            {
                var versions = assetBundleBuilder.config.version.Split('.');
                var v1s = int.Parse(versions[0]);
                var v2s = int.Parse(versions[1]);
                var v3s = int.Parse(versions[2]);
                if (++v3s >= 10)
                {
                    v3s = 0;
                    if (++v2s >= 10)
                    {
                        v1s++;
                        v2s = 0;
                    }
                }
                assetBundleBuilder.config.version = $"{v1s}.{v2s}.{v3s}";
#if UNITY_EDITOR
                EditorUtility.SetDirty(assetBundleBuilder.config);
#endif
            }
            return assetBundleBuilder.config.version;
        }

        private void DirectoryCopy(string sourceDirName, string destDirName)
        {
            if (!Directory.Exists(destDirName))
                Directory.CreateDirectory(destDirName);
            foreach (string folderPath in Directory.GetDirectories(sourceDirName, "*", SearchOption.AllDirectories))
            {
                if (!Directory.Exists(folderPath.Replace(sourceDirName, destDirName)))
                    Directory.CreateDirectory(folderPath.Replace(sourceDirName, destDirName));
            }
            foreach (string filePath in Directory.GetFiles(sourceDirName, "*.*", SearchOption.AllDirectories))
            {
                var fileDirName = Path.GetDirectoryName(filePath).Replace("\\", "/");
                var fileName = Path.GetFileName(filePath);
                var newFilePath = Path.Combine(fileDirName.Replace(sourceDirName, destDirName), fileName);
                File.Copy(filePath, newFilePath, true);
            }
        }

#if HYBRIDCLR
        public void CopyHotUpdateAssembliesToStreamingAssets(string hotfixAssembliesDstDir)
        {
            if (!Directory.Exists(hotfixAssembliesDstDir))
                Directory.CreateDirectory(hotfixAssembliesDstDir);
            var target = EditorUserBuildSettings.activeBuildTarget;
            var stripDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
            var metadataList = new List<string>();
            foreach (var assemblyName in assetBundleBuilder.AOTMetaAssemblyNames)
                CopyAssembliesToHotfixPath(metadataList, stripDir, hotfixAssembliesDstDir, assemblyName);
            stripDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
            foreach (var assemblyName in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
                CopyAssembliesToHotfixPath(null, stripDir, hotfixAssembliesDstDir, assemblyName);
            var json = Newtonsoft_X.Json.JsonConvert.SerializeObject(metadataList);
            File.WriteAllText($"{hotfixAssembliesDstDir}/MetadataList.bytes", json);
            AssetDatabase.Refresh();
        }

        private void CopyAssembliesToHotfixPath(List<string> metadataList, string stripDir, string hotfixAssembliesDstDir, string assemblyName)
        {
            if (!assemblyName.EndsWith(".dll"))
                assemblyName += ".dll";
            var dllPath = $"{stripDir}/{assemblyName}";
            if (File.Exists(dllPath))
            {
                var dllBytesPath = $"{hotfixAssembliesDstDir}/{assemblyName}.bytes";
                File.Copy(dllPath, dllBytesPath, true);
                metadataList?.Add(dllBytesPath);
            }
            if (!assetBundleBuilder.copyPdb)
                return;
            dllPath = dllPath.Replace("dll", "pdb");
            if (File.Exists(dllPath))
            {
                var pdbBytesPath = $"{hotfixAssembliesDstDir}/{assemblyName.Replace("dll", "pdb")}.bytes";
                File.Copy(dllPath, pdbBytesPath, true);
            }
        }
#endif
    }
}
#endif